/*
 * Copyright (c) 2005-2018. YingQi Anime Technology Co. Ltd. All rights reserved.
 * FileName: IPUtils.java
 * Author:   LL
 * Date:     2018年4月9日 上午11:35:23
 * Description: //模块目的、功能描述
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.sfang.common.util.ip;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;

/**
 * 〈一句话功能简述〉<br>
 * 〈功能详细描述〉
 *
 * @author LL
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public class IPUtils {

    private static Logger logger = LoggerFactory.getLogger(IPUtils.class);

    /**
     * 功能描述: <br>
     * 获取本机IP地址
     *
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static String getLocalIP() {
        InetAddress address = getLocalHostLANAddress();
        return address == null ? null : address.getHostAddress();
    }

    /**
     * 功能描述: <br>
     * 获取本机名称
     *
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static String getLocalName() {
        InetAddress address = getLocalHostLANAddress();
        return address == null ? null : address.getHostName();
    }

    /**
     * 功能描述: <br>
     * 返回本机地址对象
     *
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static InetAddress getLocalInetAddress() {
        return getLocalHostLANAddress();
    }

    /**
     * 功能描述: <br>
     * IP地址转换成InetAddress对象
     *
     * @param ip
     * @return
     * @throws UnknownHostException
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static InetAddress generateInetAddress(String ip) {
        if (StringUtils.isBlank(ip)) {
            return null;
        }

        String[] ips = ip.split("\\.");
        byte[] bs = new byte[4];
        for (int i = 0; i < ips.length; i++) {
            bs[i] = (byte) Short.parseShort(ips[i]);
        }

        InetAddress address = null;
        try {
            address = InetAddress.getByAddress(bs);
        } catch (UnknownHostException e) {
            logger.error("The length of the IP address is illegal.", e);
        }

        return address;
    }

    @SuppressWarnings("rawtypes")
    private static InetAddress getLocalHostLANAddress() {
        try {
            InetAddress candidateAddress = null;
            // 遍历所有的网络接口
            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // 在所有的接口下再遍历IP
                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // 如果是site-local地址，就是它了
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现，先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            return jdkSuppliedAddress;
        } catch (Exception e) {
            logger.error("Failed to get local IP.", e);
        }

        return null;
    }

    public static Long ipToNumber(String ip) {
        Long ips = 0L;
        String[] numbers = ip.split("\\.");
        //等价上面
        for (int i = 0; i < 4; ++i) {
            ips = ips << 8 | Integer.parseInt(numbers[i]);
        }
        return ips;
    }

    public static Integer decideIPType(String ip) {
        if (!ip.contains(".") && !ip.contains(":")) {
            return -1;
        }
        //如果是IPV4
        if (ip.contains(".")) {
            if (ip.endsWith(".")) {
                return -1;
            }
            String[] arr = ip.split("\\.");
            if (arr.length != 4) {
                return -1;
            }

            for (int i = 0; i < 4; i++) {
                if (arr[i].length() == 0 || arr[i].length() > 3) {
                    return -1;
                }
                for (int j = 0; j < arr[i].length(); j++) {
                    if (arr[i].charAt(j) >= '0' && arr[i].charAt(j) <= '9') {
                        continue;
                    }
                    return -1;
                }
                if (Integer.valueOf(arr[i]) > 255 || (arr[i].length() >= 2 && String.valueOf(arr[i]).startsWith("0"))) {
                    return -1;
                }
            }
            return 0;
        }//如果是IPV4

        //如果是IPV6
        if (ip.contains(":")) {
            if (ip.endsWith(":") && !ip.endsWith("::")) {
                return -1;
            }
            //如果包含多个“::”，一个IPv6地址中只能出现一个“::”
            if (ip.indexOf("::") != -1 && ip.indexOf("::", ip.indexOf("::") + 2) != -1) {
                return -1;
            }

            //如果含有一个“::”
            if (ip.contains("::")) {
                String[] arr = ip.split(":");
                if (arr.length > 7 || arr.length < 1) {//"1::"是最短的字符串
                    return -1;
                }
                for (int i = 0; i < arr.length; i++) {
                    if (arr[i].equals("")) {
                        continue;
                    }
                    if (arr[i].length() > 4) {
                        return -1;
                    }
                    for (int j = 0; j < arr[i].length(); j++) {
                        if ((arr[i].charAt(j) >= '0' && arr[i].charAt(j) <= '9') || (arr[i].charAt(j) >= 'A' && arr[i].charAt(j) <= 'F')
                                || (arr[i].charAt(j) >= 'a' && arr[i].charAt(j) <= 'f')) {
                            continue;
                        }
                        return -1;
                    }
                }
                return 1;
            }

            //如果不含有“::”
            if (!ip.contains("::")) {
                String[] arr = ip.split(":");
                if (arr.length != 8) {
                    return -1;
                }
                for (int i = 0; i < arr.length; i++) {
                    if (arr[i].length() > 4) {
                        return -1;
                    }
                    for (int j = 0; j < arr[i].length(); j++) {
                        if ((arr[i].charAt(j) >= '0' && arr[i].charAt(j) <= '9') || (arr[i].charAt(j) >= 'A' && arr[i].charAt(j) <= 'F')
                                || (arr[i].charAt(j) >= 'a' && arr[i].charAt(j) <= 'f')) {
                            continue;
                        }
                        return -1;
                    }
                }
                return 1;
            }
        }//如果是IPV6
        return -1;
    }

    public static long convertToLong(String ipv4) {

        String[] splits = ipv4.split("\\.");
        long l = 0;
        l = l + (Long.valueOf(splits[0], 10)) << 24;
        l = l + (Long.valueOf(splits[1], 10) << 16);
        l = l + (Long.valueOf(splits[2], 10) << 8);
        // yunsuanfu youxianji
        l = l + (Long.valueOf(splits[3], 10));

        return l;
    }

    public static String convertToIP6(String value) {
        String fullIPv6 = "";

        if ("::".equals(value)) {
            return "0000:0000:0000:0000:0000:0000:0000:0000";
        }

        String[] arr = new String[]
                {"0000", "0000", "0000", "0000", "0000", "0000", "0000", "0000"};

        if (value.startsWith("::")) {
            String[] temp = value.substring(2, value.length()).split(":");
            for (int i = 0; i < temp.length; i++) {
                String tempStr = "0000" + temp[i];
                arr[i + 8 - temp.length] = tempStr.substring(tempStr.length() - 4);
            }

        } else if (value.endsWith("::")) {
            String[] temp = value.substring(0, value.length() - 2).split(":");
            for (int i = 0; i < temp.length; i++) {
                String tempStr = "0000" + temp[i];
                arr[i] = tempStr.substring(tempStr.length() - 4);
            }

        } else if (value.contains("::")) {
            String[] tempArr = value.split("::");

            String[] temp0 = tempArr[0].split(":");
            for (int i = 0; i < temp0.length; i++) {
                String tempStr = "0000" + temp0[i];
                arr[i] = tempStr.substring(tempStr.length() - 4);
            }

            String[] temp1 = tempArr[1].split(":");
            for (int i = 0; i < temp1.length; i++) {
                String tempStr = "0000" + temp1[i];
                arr[i + 8 - temp1.length] = tempStr.substring(tempStr.length() - 4);
            }

        } else {
            String[] tempArr = value.split(":");

            for (int i = 0; i < tempArr.length; i++) {
                String tempStr = "0000" + tempArr[i];
                arr[i] = tempStr.substring(tempStr.length() - 4);
            }

        }

        fullIPv6 = org.apache.commons.lang3.StringUtils.join(arr, ":");
        return fullIPv6;
    }

    public static String padding(String str, int strLength, String type) {
        int strLen = str.length();
        StringBuffer sb = null;
        while (strLen < strLength) {
            sb = new StringBuffer();
            //sb.append("0").append(str);// 左补0
            sb.append(str).append(type);//右补0
            str = sb.toString();
            strLen = str.length();
        }
        return str;
    }

    public static BigInteger convertIPV6ToBigInteger(String ip) {
        Integer ipType = decideIPType(ip);
        if (ipType == 0)
            return new BigInteger("-1");

        BigInteger ipValue = BigInteger.ZERO;
        int compressIndex = ip.indexOf("::");

        if (compressIndex != -1) {
            String part1s = ip.substring(0, compressIndex);
            String part2s = ip.substring(compressIndex + 1);
            BigInteger part1 = convertIPV6ToBigInteger(part1s);
            BigInteger part2 = convertIPV6ToBigInteger(part2s);
            int part1hasDot = 0;
            char ch[] = part1s.toCharArray();
            for (char c : ch) {
                if (c == ':') {
                    part1hasDot++;
                }
            }
            ipValue = part1.shiftLeft(16 * (7 - part1hasDot)).add(part2);
        } else if (ip.indexOf(":") > -1) {
            String[] str = ip.split(":");
            for (int i = 0; i < str.length; i++) {
                //::1
                if (str[i].isEmpty()) {
                    str[i] = "0";
                }
                ipValue = ipValue.add(BigInteger.valueOf(Long.valueOf(str[i], 16))
                        .shiftLeft(16 * (str.length - i - 1)));
            }
        } else {
            String[] str = new String[8];
            for (int index = 0; index < 8; index++) {
                String childStr = ip.substring(index * 4,
                        (index + 1) * 4);
                str[index] = childStr;
            }

            for (int i = 0; i < str.length; i++) {
                if (str[i].isEmpty() || str[i].trim().equals("0000")) {
                    str[i] = "0";
                }
                ipValue = ipValue.add(BigInteger.valueOf(Long.valueOf(str[i], 16))
                        .shiftLeft(16 * (str.length - i - 1)));
            }
        }
        return ipValue;

    }

    public static String convertIP4ToString(BigInteger ipInBigInt) {
        byte[] bytes = ipInBigInt.toByteArray();
        byte[] unsignedBytes = Arrays.copyOfRange(bytes, 1, bytes.length);
        // 去除符号位
        try {
            String ip = InetAddress.getByAddress(unsignedBytes).toString();
            return ip.substring(ip.indexOf('/') + 1).trim();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        System.out.println(ipToNumber("116.233.23.20"));
    }


}
